package com.zhuandaonet.springjpa.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.zhuandaonet.common.constant.Code;
import com.zhuandaonet.common.domain.resp.Resp;
import com.zhuandaonet.common.exception.ServiceException;
import com.zhuandaonet.springjpa.dao.IDao;
import com.zhuandaonet.springjpa.entity.EntityImpl;
import com.zhuandaonet.springjpa.entity.IEntity;
import com.zhuandaonet.springjpa.service.IService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import javax.transaction.Transactional;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public abstract class ServiceImpl<T extends IEntity,ID extends Serializable> implements IService<T,ID> {

    public abstract IDao<T,ID> getRepository();

    @Transactional
    @Override
    public T save(T t) throws SecurityException {
        log.debug(">>>>>>>> 保存实体，实体数据为：{}",t);
        try {
            t = getRepository().save(t);
            log.debug(">>>>>>>> 保存后的结果:{}",t);
            return t;
        }catch (Exception e){
            log.info(">>>>>>> 保存" + t.getClass().getName() +"时出错，要保存的信息为：{}",t);
            ServiceException exception = ServiceException.builder().status(Code.Status.INTERNAL_SERVER_ERROR).errorCode(Code.Error.UNKNOWN).message("保存失败！").build();
            exception.setStackTrace(e.getStackTrace());
            e.printStackTrace();
            throw exception;
        }
    }

    @Override
    public T saveAndFush(T t) throws ServiceException {
        log.debug(">>>>>>>> 保存实体，实体数据为：{}",t);
        try {
            t = getRepository().saveAndFlush(t);
            log.debug(">>>>>>>> 更新后的结果:{}",t);
            return t;
        }catch (Exception e){
            log.info(">>>>>>> 保存" + t.getClass().getName() +"时出错，要保存的信息为：{}",t);
            ServiceException exception = ServiceException.builder().status(Code.Status.INTERNAL_SERVER_ERROR).errorCode(Code.Error.UNKNOWN).message("保存失败").build();
            exception.setStackTrace(e.getStackTrace());
            e.printStackTrace();
            throw exception;
        }
    }

    @Override
    public T getOneById(ID id) throws ServiceException {
        log.debug(">>>>>>>> 根据ID获取实体，实体ID为：{}",id);
        try {
            T t = getRepository().getOne(id);
            log.debug(">>>>>>>> 查询结果：{}",t);
            return t;
        }catch (Exception e){
            log.info(">>>>>>> 根据ID" + id +"获取实体时出错，传入的ID为：{}",id);
            ServiceException exception = ServiceException.builder().status(Code.Status.INTERNAL_SERVER_ERROR).errorCode(Code.Error.UNKNOWN).message("失败！").build();
            exception.setStackTrace(e.getStackTrace());
            e.printStackTrace();
            throw exception;
        }
    }

    @Transactional
    @Override
    public void delete(ID id) throws ServiceException {
        log.debug(">>>>>>>> 根据ID删除实体，实体ID为：{}",id);
        try {
            getRepository().deleteById(id);
        }catch (Exception e){
            log.info(">>>>>>> 根据ID删除实体时出错，传入的ID为：{}",id);
            ServiceException exception = ServiceException.builder().status(Code.Status.INTERNAL_SERVER_ERROR).errorCode(Code.Error.UNKNOWN).message("删除失败！").build();
            exception.setStackTrace(e.getStackTrace());
            e.printStackTrace();
            throw exception;
        }
    }

    @Transactional
    @Override
    public void delete(String[] ids) throws ServiceException {
        log.debug(">>>>>>>> 根据实体ID的集合删除实体，实体ID集合：{}", JSONObject.toJSONString(ids));
        try {
            List<T> ts = new ArrayList<>();
            for(int i=0;i<ids.length-1;i++){
                EntityImpl entity = new EntityImpl(){
                    @Override
                    public Resp toResp() {
                        return null;
                    }
                };
                entity.setId(ids[i]);
                ts.add((T)entity);
            }
            getRepository().deleteAll(ts);
        }catch (Exception e){
            log.info(">>>>>>> 根据ID的集合删除实体时出错，传入的ID集合为：{}",JSONObject.toJSONString(ids));
            ServiceException exception = ServiceException.builder().status(Code.Status.INTERNAL_SERVER_ERROR).errorCode(Code.Error.UNKNOWN).message("删除失败！").build();
            exception.setStackTrace(e.getStackTrace());
            e.printStackTrace();
            throw exception;
        }
    }

    @Transactional
    @Override
    public void delete(List<T> ts) throws ServiceException {
        log.debug(">>>>>>>> 根据实体集合删除实体，实体集合：{}",ts);
        try {
            getRepository().deleteAll(ts);
        }catch (Exception e){
            log.info(">>>>>>> 根据实体的集合删除实体时出错，传入的实体集合为：{}",ts);
            ServiceException exception = ServiceException.builder().status(Code.Status.INTERNAL_SERVER_ERROR).errorCode(Code.Error.UNKNOWN).message("删除失败！").build();
            exception.setStackTrace(e.getStackTrace());
            e.printStackTrace();
            throw exception;
        }
    }

    @Override
    public List<T> findAll() throws ServiceException {
        log.debug(">>>>>>>> 获取所有实体。");
        try {
            List<T> ts = getRepository().findAll();
            log.debug(">>>>>>>> 查询结果：{}",ts);
            return ts;
        }catch (Exception e){
            log.info(">>>>>>> 获取所有实体时出错！");
            ServiceException exception = ServiceException.builder().status(Code.Status.INTERNAL_SERVER_ERROR).errorCode(Code.Error.UNKNOWN).message("查询失败！").build();

            exception.setStackTrace(e.getStackTrace());
            e.printStackTrace();
            throw exception;
        }
    }

    @Override
    public Page<T> findAll(Pageable pageable) throws ServiceException {
        log.debug(">>>>>>>> 分页获取所有实体。");
        try {
            Page<T> ts = getRepository().findAll(pageable);
            log.debug(">>>>>>>> 查询结果：{}",ts);
            return ts;
        } catch (Exception e) {
            log.info(">>>>>>> 分页获取所有实体时出错！");
            ServiceException exception = ServiceException.builder().status(Code.Status.INTERNAL_SERVER_ERROR).errorCode(Code.Error.UNKNOWN).message("查询失败！").build();
            exception.setStackTrace(e.getStackTrace());
            e.printStackTrace();
            throw exception;
        }
    }

    @Override
    public Boolean exist(T t) throws ServiceException {
        log.debug(">>>>>>>> 根据条件判断实体是否存在。");
        try {
            log.debug(">>>>>>>> 条件：{}",t);
            Boolean bl = getRepository().exists(Example.of(t));
            log.debug(">>>>>>>>> 结果:{}",bl);
            return bl;
        }catch (Exception e){
            log.info(">>>>>>> 判断实体是否存在时出错！");
            ServiceException exception = ServiceException.builder().status(Code.Status.INTERNAL_SERVER_ERROR).errorCode(Code.Error.UNKNOWN).message("操作失败！").build();
            exception.setStackTrace(e.getStackTrace());
            e.printStackTrace();
            throw exception;
        }
    }

    @Override
    public Boolean exist(ID id) throws ServiceException {
        log.debug(">>>>>>>> 根据ID判断实体是否存在。");
        try {
            log.debug(">>>>>>>> ID：{}",id);
            Boolean bl = getRepository().existsById(id);
            log.debug(">>>>>>>>> 结果:{}",bl);
            return bl;
        }catch (Exception e){
            log.info(">>>>>>> 根据ID判断实体是否存在时出错！");
            ServiceException exception = ServiceException.builder().status(Code.Status.INTERNAL_SERVER_ERROR).errorCode(Code.Error.UNKNOWN).message("操作失败！").build();
            exception.setStackTrace(e.getStackTrace());
            e.printStackTrace();
            throw exception;
        }
    }

    @Override
    public Long count(T t) throws ServiceException {
        log.debug(">>>>>>>> 根据条件统计实体数量。");
        try {
            log.debug(">>>>>>>> 条件：{}",t);
            Long count = getRepository().count(Example.of(t));
            log.debug(">>>>>>>> 结果:{}",count);
            return count;
        }catch (Exception e){
            log.info(">>>>>>> 根据实体条件统计实体数量时出错！");
            ServiceException exception = ServiceException.builder().status(Code.Status.INTERNAL_SERVER_ERROR).errorCode(Code.Error.UNKNOWN).message("统计失败！").build();
            exception.setStackTrace(e.getStackTrace());
            e.printStackTrace();
            throw exception;
        }
    }

    @Override
    public Long count() throws ServiceException {
        try {
            Long count = getRepository().count();
            log.debug(">>>>>>>> 统计结果:{}",count);
            return count;
        }catch (Exception e){
            log.info(">>>>>>> 实体数量时出错！");
            ServiceException exception = ServiceException.builder().status(Code.Status.INTERNAL_SERVER_ERROR).errorCode(Code.Error.UNKNOWN).message("统计失败！").build();
            exception.setStackTrace(e.getStackTrace());
            e.printStackTrace();
            throw exception;
        }
    }
}
